package modelo;

public class GaussSeidel {
	
	public MatrizCuadrada generarMatrizN(ConjuntoMatriz conjunto){
		
		MatrizCuadrada resultado = new MatrizCuadrada(conjunto.getDimension());
		
		for(int fila = 1; fila <= conjunto.getDimension();fila++){
			
			for(int columna = 1; columna <= conjunto.getDimension();columna++){
				
				if(fila	>= columna){
					
					double valor = conjunto.obtenerValorEn(fila, columna);
					
					resultado.colocarValorEn(valor, fila-1, columna-1);
				}
			}
		}
		return resultado;
	}

	public MatrizCuadrada generarMatrizP(ConjuntoMatriz conjunto){
		
		MatrizCuadrada resultado = new MatrizCuadrada(conjunto.getDimension());
		
		for(int fila = 1; fila <= conjunto.getDimension();fila++){
			
			for(int columna = 1; columna <= conjunto.getDimension();columna++){
				
				if(columna > fila){
					
					double valor = conjunto.obtenerValorEn(fila, columna);
					
					resultado.colocarValorEn(valor, fila-1, columna-1);
				}
			}
		}
		return resultado;
	}
	
	public MatrizCuadrada invertirN(MatrizCuadrada N){
		
		MatrizCuadrada resultado = new MatrizCuadrada(N.getDimension());
		
		Jacobi jac = new Jacobi();
		
		for(int iteracion = 0; iteracion < N.getDimension(); iteracion++){
			
			double [] b = new double[N.getDimension()];
			
			b[iteracion] = 1;
			
			double [] columna = jac.jacobi(N, b);
			
			this.colocarColumnaEnMatriz(resultado,columna,iteracion);
		}
		return resultado;
	}
	
	private void colocarColumnaEnMatriz(MatrizCuadrada resultado,double[] columna, int iteracion) {

		for(int posicionEnVector = 0; posicionEnVector < resultado.getDimension(); posicionEnVector++){
		
			resultado.colocarValorEn(columna[posicionEnVector], posicionEnVector, iteracion);
		}
	}

	public void gaussSeidel(ConjuntoMatriz conjunto){
		
		int iteracion = 1;
		
		Operacion op= new Operacion();
		
		double [] semilla = op.generarSemillaNula(conjunto.getDimension());
		
		double [] b = op.generarVectorB(conjunto);
		
		MatrizCuadrada N = this.generarMatrizN(conjunto);
		
		MatrizCuadrada invN = this.invertirN(N);
		
		MatrizCuadrada P = this.generarMatrizP(conjunto);
		
		MatrizCuadrada invNxP = op.multiplicarMatrices(invN, P);
		
		double [] primerTermino = op.multiplicarMatrizPorVector(invN, b);
		
		double [] valorActual = primerTermino;
		
		double [] valorAnterior = new double [primerTermino.length];
	
		while(op.calcularErrorRelativo(valorActual, valorAnterior) >= 0.001){
			
			valorAnterior = valorActual;
			
			double [] segundoTermino = op.multiplicarMatrizPorVector(invNxP, valorAnterior);
			
			valorActual = op.restarVectores(primerTermino, segundoTermino);
					
			double resta = op.calulcarRestaDeLogaritmos(valorActual,valorAnterior,semilla);
			
			System.out.print("\n El numero de iteracion es:");
			
			System.out.print(iteracion);
			
			System.out.print("\n la resta de logaritmoss es :");
		
			System.out.print(resta);
			
			iteracion++;
		}
		this.mostrarResultado(valorActual, op.calcularErrorRelativo(valorActual, valorAnterior));
	}
	
	private void mostrarResultado(double[] valorActual, double calcularErrorRelativo) {
		
		System.out.print("\n\nEl resultado por Gauss Seidel es : \n");
		
		for(int posicion = 0; posicion < valorActual.length; posicion++){
			
			System.out.print(valorActual[posicion]);
		
			System.out.print("\n");
		}
		
		System.out.print("El error cometido por Gauss Seidel fue de : \n");
		
		System.out.print(calcularErrorRelativo);
	}
}
